package resp

import (
	"context"
	"errors"
	"fmt"
	"github.com/starmotioncf/common/lang"
	"github.com/starmotioncf/common/log"
	"github.com/starmotioncf/soutchatinternal/errcode"
	"net/http"
	"sync"
	"time"

	"github.com/gin-gonic/gin"
)

var getErrCodeI18nFn func(ctx *gin.Context, key string) *lang.I18n
var getLangFnLock sync.Mutex

func SetErrCodeMsgFn(fn func(ctx *gin.Context, key string) *lang.I18n) {
	getLangFnLock.Lock()
	defer getLangFnLock.Unlock()
	getErrCodeI18nFn = fn
}

// 获取翻译的错误消息
func getErrCodeMsg(ctx *gin.Context, code errcode.ErrCode, def string) string {
	if getErrCodeI18nFn == nil {
		return def
	}
	key := fmt.Sprintf("errcode.%d", code)
	langT := getErrCodeI18nFn(ctx, key)
	if langT.Exist() {
		return langT.TranslateTo(ctx.GetHeader("lang"))
	}
	return def
}

type Resp struct {
	Code errcode.ErrCode `json:"code"`
	Msg  string          `json:"msg"`
	Data any             `json:"data"`
	Ts   int64           `json:"ts"` //毫秒时间戳
}

// PageList 旧版本的翻页数据响应
type PageList struct {
	Total int64 `json:"total"`
	List  any   `json:"list"`
}

var arr = make([]struct{}, 0)
var maps = make(map[string]struct{}, 0)

// ReturnMustString 根据参数判断 返回约定的json格式 , data = nil时， res = ""
func ReturnMustString(ctx *gin.Context, data any, err error) {
	if data == nil {
		data = ""
	}
	Return(ctx, data, err)
}

// ReturnMustInt 根据参数判断 返回约定的Int格式 , data = nil时， res = 0
func ReturnMustInt(ctx *gin.Context, data any, err error) {
	if data == nil {
		data = 0
	}
	Return(ctx, data, err)
}

// ReturnMustArr 根据参数判断 返回约定的json格式 , data = nil时， res = []
func ReturnMustArr(ctx *gin.Context, data any, err error) {
	if data == nil {
		data = arr
	}
	Return(ctx, data, err)
}

// ReturnMustJson 根据参数判断 返回约定的json格式 , data = nil时， res = {}
func ReturnMustJson(ctx *gin.Context, data any, err error) {
	if data == nil {
		data = maps
	}
	Return(ctx, data, err)
}

// Return 根据参数判断 返回约定的json格式, data = nil时， res = null
func Return(ctx *gin.Context, data any, err error) {
	if err != nil {
		Error(ctx, err)
	} else {
		Success(ctx, data)
	}
}

// Success 成功返回数据，httpCode=200, 返回约定的json格式
func Success(ctx *gin.Context, data any) {
	ReturnJson(ctx, errcode.OK, "ok", data)
}

// Error 成功失败数据，httpCode=200, 返回约定的json格式
func Error(ctx *gin.Context, err error) {
	code, msg := renderCodeMsg(ctx, err)
	ReturnJson(ctx, code, msg, nil)
}

// ReturnJson  返回约定的json格式
func ReturnJson(ctx *gin.Context, code errcode.ErrCode, msg string, data any) {
	ctx.JSON(http.StatusOK, CreateResp(code, msg, data))
}

func CreateResp(code errcode.ErrCode, msg string, data any) Resp {
	return Resp{
		Code: code,
		Msg:  msg,
		Data: data,
		Ts:   time.Now().UnixMilli(),
	}
}

func RedirectUrl(ctx *gin.Context, code int, url string) {
	ctx.Redirect(code, url)
}

// Abort 输出并终止程序，自定义httpCode 和输出消息
func Abort(ctx *gin.Context, status int, err error) {
	_ = ctx.AbortWithError(status, err)
}

// renderCodeMsg 将error转成code，msg
func renderCodeMsg(ctx *gin.Context, err error) (errcode.ErrCode, string) {
	code := errcode.ErrUnknown
	msg := code.Error()
	switch v := err.(type) {
	case errcode.ErrCode:
		code = v
		msg = getErrCodeMsg(ctx, code, v.Error())
	case errcode.ErrWrap:
		code = v.Code()
		msg = v.Error()
	default:
		if !errors.Is(err, context.Canceled) {
			log.WithContext(ctx).Error(fmt.Sprintf("renderCodeMsg err:%+v", err))
		}
	}
	return code, msg
}
